package com.woniu113.junk.order.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.json.JSONUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.woniu113.junk.commons.util.AliyunOSSUtil;
import com.woniu113.junk.order.client.SiteClient;
import com.woniu113.junk.order.client.UserClient;
import com.woniu113.junk.order.client.dto.*;
import com.woniu113.junk.order.client.form.IntegralForm;
import com.woniu113.junk.order.dto.*;
import com.woniu113.junk.order.exception.OrderInfoException;
import com.woniu113.junk.order.form.orderInfo.OkOderInfoForm;
import com.woniu113.junk.order.form.orderInfo.ScoreForm;
import com.woniu113.junk.order.model.OrderInfo;
import com.woniu113.junk.order.mapper.OrderInfoMapper;
import com.woniu113.junk.order.model.OrderLog;
import com.woniu113.junk.order.param.orderInfo.*;

import com.woniu113.junk.order.service.OrderInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu113.junk.order.service.OrderLogService;
import com.woniu113.junk.order.util.Data;
import org.checkerframework.checker.units.qual.A;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 蜡笔没了小新
 * @since 2024年10月16日
 */
@Service
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {
    @Resource
    private OrderInfoMapper oim;
    @Resource
    private UserClient uc;
    @Resource
    private SiteClient sc;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private OrderInfoService ois;
    @Resource
    private OrderLogService ols;
    @Resource
    private AliyunOSSUtil aliyunOSSUtil;
    @Resource
    private AlipayClient alipayClient;
    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    private ObjectMapper objectMapper;

    /**
     * 用户下预约单
     * */
    @Override
    public void appointment(AddOrderInfoParam param) {
        Integer userId = param.getUserId();
        LocalDateTime startTime = param.getStartTime();
        LocalDateTime endTime = param.getEndTime();
        String typeName = param.getTypeName();
        String typeWeight = param.getTypeWeight();
        Integer addressId = param.getAddressId();
        String orderInfo = typeName+":"+typeWeight;

        //判断传入参数是否正确
        if (userId == null) throw new OrderInfoException("用户ID不能为空", 5302);
        if (startTime == null) throw new OrderInfoException("开始时间不能为空", 5302);
        if (endTime == null) throw new OrderInfoException("结束时间不能为空", 5302);
        if (typeName == null || typeName.isEmpty()) throw new OrderInfoException("订单信息不能为空", 5302);
        if (typeWeight == null || typeWeight.isEmpty()) throw new OrderInfoException("订单信息不能为空", 5302);
        if (addressId == null) throw new OrderInfoException("地址ID不能为空", 5302);
        if (endTime.isBefore(startTime)) throw new OrderInfoException("结束时间不能早于开始时间", 5302);
        UserInfoDTO userInfoDTO = uc.selectIntegral(userId).getData();
        if (userInfoDTO == null || userInfoDTO.getUserState()!=0) throw new OrderInfoException("用户不存在",5302);
        AddressInfoDTO infoDTO = uc.addressById(addressId).getData();
        if (infoDTO == null || infoDTO.getAddressState() != 0) throw new OrderInfoException("地址不存在",5302);

        //根据地址经纬度匹配最近站点
        BigDecimal longitude = infoDTO.getLongitude();//用户地址经度
        BigDecimal latitude = infoDTO.getLatitude();//用户地址纬度
        //获取和用户同区域的站点集合
        List<StationInfoDTO> stationInfoDTOS = sc.findChildStationByCityAndCounty(infoDTO.getCity(), infoDTO.getCounty()).getData();
        //符合条件(距离不超过五公里的站点的集合)
        List<StationCompareDTO> nearbyStations = new ArrayList<>();
        for (StationInfoDTO stationInfoDTO : stationInfoDTOS) {
            double distance = calculateDistance(latitude, longitude, stationInfoDTO.getLatitude(), stationInfoDTO.getLongitude());
            // 筛选出距离不超过5公里的站点
            if (distance <= 5.0) {
                StationCompareDTO compareDTO = new StationCompareDTO();
                compareDTO.setStationId(stationInfoDTO.getStationId());
                compareDTO.setDistance(distance);
                nearbyStations.add(compareDTO);
            }
        }
        //根据距离排序
        nearbyStations.sort(Comparator.comparingDouble(StationCompareDTO::getDistance));
        StationCompareDTO stationCompareDTO = nearbyStations.get(0);
        Integer stationId = stationCompareDTO.getStationId();
        Double distance = stationCompareDTO.getDistance();
        StationInfoDTO data = sc.findStationInfoById(stationId).getData();

        //将数据存入redis中，创建订单的Redis的键
        String orderNum = UUID.randomUUID().toString().replaceAll("-", "");
        String wasteOrderRedisKey = "waste:orderInfo:"+orderNum;
        System.out.println("订单编号："+orderNum);
        //创建一个 HashMap 来存储订单信息
        Map<String, String> orderMap = new HashMap<>();
        orderMap.put("order_num",orderNum);
        orderMap.put("user_id",String.valueOf(userId));
        orderMap.put("user_phone", userInfoDTO.getUserPhone());
        orderMap.put("start_time",DateUtil.format(startTime, "yyyy-MM-dd HH:mm:ss"));
        orderMap.put("end_time",DateUtil.format(endTime, "yyyy-MM-dd HH:mm:ss"));
        orderMap.put("order_info",orderInfo);
        orderMap.put("create_time",DateUtil.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"));
        orderMap.put("order_state",String.valueOf(Data.ORDER_STATE_WAITING));
        orderMap.put("station_id",String.valueOf(stationId));
        orderMap.put("station_name",data.getStationName());
        orderMap.put("station_phone",data.getStationPhone());
        orderMap.put("state",String.valueOf(Data.ORDER_INFO_STATE_NORMAL));
        System.out.println("订单信息: " + orderMap);
        //将订单信息使用哈希存储存入 Redis
        stringRedisTemplate.opsForHash().putAll(wasteOrderRedisKey,orderMap);
        // 新增下单操作记录
        OrderLogDTO orderLog = new OrderLogDTO();
        orderLog.setOrderNum(orderNum);
        orderLog.setLogTime(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
        orderLog.setUserId(userId);
        orderLog.setUserType("用户");
        orderLog.setLogDesc("预约废品回收上门服务成功");
        // 使用列表存储日志
        String orderLogRedisKey = "waste:orderLog:" + orderNum;
        // 序列化日志并添加到 Redis 列表
        stringRedisTemplate.opsForList().rightPush(orderLogRedisKey, JSONUtil.toJsonStr(orderLog));
        // 启动定时检查订单状态
        checkOrderStatus(orderNum, nearbyStations);
    }

    /**
     * 开启定时检查
     * */
    private void checkOrderStatus(String orderNum, List<StationCompareDTO> nearbyStations) {
        new Thread(() -> {
            try {
                Thread.sleep(10 * 60 * 1000); // 等待 10 分钟
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            updateOrderStatus(orderNum, nearbyStations);
        }).start();
    }

    /**
     * 判断订单状态
     * */
    private boolean isOrderReceived(String orderNum) {
        // 检查订单状态
        String wasteOrderRedisKey = "waste:orderInfo:"+orderNum;
        Map<Object, Object> orderData = stringRedisTemplate.opsForHash().entries(wasteOrderRedisKey);
        if (orderData.isEmpty()) throw new OrderInfoException("订单不存在", 5303);
        Integer orderState = Integer.valueOf((String) orderData.get("order_state"));
        Integer state = Integer.valueOf((String) orderData.get("state"));
        if (state!=Data.ORDER_INFO_STATE_NORMAL) throw new OrderInfoException("订单不存在", 5303);
        if (orderState == Data.ORDER_STATE_WAITING){
            return false;
        }else {
            return true;
        }
    }

    /**
     * 检查订单并将数据存入数据库表中
     * */
    private void updateOrderStatus(String orderNum, List<StationCompareDTO> nearbyStations) {
        String wasteOrderRedisKey = "waste:orderInfo:" + orderNum;
        Map<Object, Object> orderInfo = stringRedisTemplate.opsForHash().entries(wasteOrderRedisKey);
        System.out.println("取消订单数据是：" + orderInfo);
        if (orderInfo != null && !orderInfo.isEmpty()) {
            // 检查订单状态
            if (!isOrderReceived(orderNum)) {
                int currentStationIndex = Integer.parseInt((String) orderInfo.get("station_id"));
                if (currentStationIndex < nearbyStations.size() - 1) {
                    // 更新站点 ID 和名称
                    currentStationIndex++;
                    StationCompareDTO nextStation = nearbyStations.get(currentStationIndex);
                    StationInfoDTO data = sc.findStationInfoById(nextStation.getStationId()).getData();
                    orderInfo.put("station_id", String.valueOf(data.getStationId()));
                    orderInfo.put("station_name", data.getStationName());
                    stringRedisTemplate.opsForHash().putAll(wasteOrderRedisKey, orderInfo);
                    // 重新启动检查
                    checkOrderStatus(orderNum, nearbyStations);
                } else {
                    //将订单取消存入数据库中
                    OrderInfo info  = objectMapper.convertValue(orderInfo, OrderInfo.class);
                    info.setOrderState(Data.ORDER_STATE_CANCEL);
                    info.setUserId(Integer.valueOf((String) orderInfo.get("user_id")));
                    info.setUserPhone((String) orderInfo.get("user_phone"));
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                    info.setStartTime(LocalDateTime.parse((String) orderInfo.get("start_time"), formatter));
                    info.setEndTime(LocalDateTime.parse((String) orderInfo.get("end_time"), formatter));
                    info.setCreateTime(LocalDateTime.parse((String) orderInfo.get("create_time"), formatter));
                    info.setOrderInfo((String) orderInfo.get("order_info"));
                    info.setStationId(Integer.valueOf((String) orderInfo.get("station_id")));
                    info.setStationName((String) orderInfo.get("station_name"));
                    info.setStationPhone((String) orderInfo.get("station_phone"));
                    info.setOrderNum(orderNum);
                    info.setCancelReason("用户范围五公里内无法接单，订单已取消");
                    ois.save(info);
                    //将日志也存入redis
                    OrderLogDTO orderLog = new OrderLogDTO();
                    orderLog.setOrderNum(orderNum);
                    orderLog.setLogTime(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
                    orderLog.setUserType("系统");
                    orderLog.setLogDesc("用户范围五公里内无法接单，订单已取消");
                    // 使用列表存储日志
                    String orderLogRedisKey = "waste:orderLog:" + orderNum;
                    // 序列化日志并添加到 Redis 列表
                    stringRedisTemplate.opsForList().rightPush(orderLogRedisKey, JSONUtil.toJsonStr(orderLog));
                    //取出全部日志，依次存入mysql数据库表
                    String orderLogJson;
                    while ((orderLogJson = stringRedisTemplate.opsForList().leftPop(orderLogRedisKey)) != null) {
                        try {
                            // 反序列化日志
                            OrderLogDTO log = objectMapper.readValue(orderLogJson, OrderLogDTO.class);
                            String logTimeString = log.getLogTime(); // 这里假设 log.getLogTime() 返回的类型是 String
                            LocalDateTime logTime = LocalDateTime.parse(logTimeString, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
                            OrderLog logs = objectMapper.readValue(orderLogJson, OrderLog.class);
                            logs.setLogTime(logTime);
                            // 将日志存入数据库
                            ols.save(logs);
                        } catch (Exception e) {
                            // 处理反序列化和数据库存储时的异常
                            System.err.println("Error processing log: " + e.getMessage());
                        }
                    }
                    // 删除Redis中的日志项
                    stringRedisTemplate.delete(orderLogRedisKey);
                    // 超过所有可用站点，删除redis中订单
                    stringRedisTemplate.delete(wasteOrderRedisKey);
                }
            }
        }
    }

    /**
     * 该方法已废弃
     * */
    @Override
    public void acceptOrder(String orderNum, Integer adminId) {
        //判断传入参数是否正确
        if (adminId == null) throw new OrderInfoException("用户ID不能为空", 5302);
        if (orderNum == null || orderNum.isEmpty()) throw new OrderInfoException("订单编号不能为空",5302);
        AdminInfoDTO adminInfoDTO = uc.selectAdminById(adminId).getData();

        //添加redis分布式锁
        String wasteOrderRedisKey = "waste:orderInfo:" + orderNum;
        String lockKey = "lock:" + wasteOrderRedisKey;
        Boolean isLocked = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, "locked", 10, TimeUnit.SECONDS);
        if (isLocked == null || !isLocked) {
            throw new OrderInfoException("订单正在被处理，请稍后重试", 5304);
        }
        //取出订单数据
        try {
            Map<Object, Object> orderData = stringRedisTemplate.opsForHash().entries(wasteOrderRedisKey);
            if (orderData.isEmpty()) throw new OrderInfoException("订单不存在", 5303);
            Integer orderState = Integer.valueOf((String) orderData.get("order_state"));
            Integer state = Integer.valueOf((String) orderData.get("state"));
            if (orderState!=Data.ORDER_STATE_WAITING || state!=Data.ORDER_INFO_STATE_NORMAL) throw new OrderInfoException("订单不存在", 5303);
            //将回收小哥信息加入订单
            orderData.put("rider_id",adminId);
            orderData.put("rider_phone",adminInfoDTO.getAdminPhone());
            stringRedisTemplate.opsForHash().putAll(wasteOrderRedisKey,orderData);
        }finally {
            stringRedisTemplate.delete(lockKey);
        }
    }

    /**
     * 查询能够接单的骑士信息
     * */
    @Override
    public Page<AdminInfoDTO> findSuitableRider(FindSuitableRiderParam param) {
        //判断传入参数是否正确
        if (param.getOrderNum() == null || param.getOrderNum().isEmpty()) throw new OrderInfoException("订单编号不能为空",5302);
        OrderInfo orderInfo = ois.getById(param.getOrderNum());
        if (orderInfo.getOrderState() != Data.ORDER_STATE_DISTRIBUTE || orderInfo.getState() == Data.ORDER_INFO_STATE_DELETE) throw new OrderInfoException("订单不存在", 5303);
        //获取判断所需的数据
        LocalDateTime startTime = orderInfo.getStartTime();
        LocalDateTime endTime = orderInfo.getEndTime();
        Integer stationId = orderInfo.getStationId();
        StationInfoDTO data = sc.findStationInfoById(stationId).getData();
        String city = data.getCity();
        String county = data.getCounty();

        //查询时间冲突的订单
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("order_state",Data.ORDER_STATE_RECEIVED).eq("state",Data.ORDER_INFO_STATE_NORMAL);
        List<OrderInfo> orderInfos = oim.selectList(wrapper);
        FindSuitableRiderDTO riderDTO = new FindSuitableRiderDTO();
        riderDTO.setStationId(stationId);
        riderDTO.setPageNum(param.getPageNum());
        riderDTO.setPageSize(param.getPageSize());
        if (orderInfos.isEmpty()){
            //没有时间冲突的订单
            Page<AdminInfoDTO> dtoPage = uc.findByStationId(riderDTO).getData();
            return dtoPage;
        }else {
            //将冲突的骑手ID存入
            List<Integer> list = new ArrayList<>();
            for (OrderInfo info : orderInfos) {
                list.add(info.getRiderId());
            }
            riderDTO.setAdminId(list);
            Page<AdminInfoDTO> dtoPage = uc.findByStationId(riderDTO).getData();
            return dtoPage;
        }
    }

    @Override
    public List<AdminInfoDTO> findAdmin(FindByStationParam param) {
        if (param.getStartTime() == null || param.getEndTime() == null || param.getStationId() ==null) throw new OrderInfoException("参数不能为空",5302);
        LocalDateTime startTime = param.getStartTime();
        LocalDateTime endTime = param.getEndTime();
        int stationId = param.getStationId();
        //查询时间冲突的骑手ID数组
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("station_id",stationId).eq("order_state", Data.ORDER_STATE_RECEIVED).eq("start_time",startTime).eq("end_time",endTime);
        List<OrderInfo> infos = oim.selectList(wrapper);
        ArrayList<Integer> list = new ArrayList<>();
        if (infos.size()!=0){
            for (OrderInfo info : infos) {
                list.add(info.getRiderId());
            }
        }
        //排除冲突的骑手ID
        FindAdminDTO dto = new FindAdminDTO();
        dto.setList(list);
        dto.setStationId(stationId);
        List<AdminInfoDTO> adminInfoDTOList = uc.findAdmin(dto).getData();
        return adminInfoDTOList;
    }

    @Override
    public void orderTaking(String orderNum, int admin) {
        String wasteOrderRedisKey = "waste:orderInfo:" + orderNum;
        Map<Object, Object> orderInfo = stringRedisTemplate.opsForHash().entries(wasteOrderRedisKey);
        System.out.println("接单的数据是：" + orderInfo);
        //订单数据写入数据库
        OrderInfo info  = objectMapper.convertValue(orderInfo, OrderInfo.class);
        info.setOrderState(Data.ORDER_STATE_DISTRIBUTE);
        info.setUserId(Integer.valueOf((String) orderInfo.get("user_id")));
        info.setUserPhone((String) orderInfo.get("user_phone"));
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        info.setStartTime(LocalDateTime.parse((String) orderInfo.get("start_time"), formatter));
        info.setEndTime(LocalDateTime.parse((String) orderInfo.get("end_time"), formatter));
        info.setCreateTime(LocalDateTime.parse((String) orderInfo.get("create_time"), formatter));
        info.setOrderInfo((String) orderInfo.get("order_info"));
        info.setStationId(Integer.valueOf((String) orderInfo.get("station_id")));
        info.setStationName((String) orderInfo.get("station_name"));
        info.setStationPhone((String) orderInfo.get("station_phone"));
        info.setOrderNum(orderNum);
        ois.save(info);
        //日志
        OrderLogDTO orderLog = new OrderLogDTO();
        orderLog.setOrderNum(orderNum);
        orderLog.setLogTime(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
        orderLog.setUserId(admin);
        orderLog.setUserType("站长");
        orderLog.setLogDesc("站长已接单，订单等待分配骑手");
        // 使用列表存储日志
        String orderLogRedisKey = "waste:orderLog:" + orderNum;
        // 序列化日志并添加到 Redis 列表
        stringRedisTemplate.opsForList().rightPush(orderLogRedisKey, JSONUtil.toJsonStr(orderLog));
        //取出全部日志，依次存入mysql数据库表
        String orderLogJson;
        while ((orderLogJson = stringRedisTemplate.opsForList().leftPop(orderLogRedisKey)) != null) {
            try {
                // 反序列化日志
                OrderLogDTO log = objectMapper.readValue(orderLogJson, OrderLogDTO.class);
                String logTimeString = log.getLogTime(); // 这里假设 log.getLogTime() 返回的类型是 String
                LocalDateTime logTime = LocalDateTime.parse(logTimeString, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
                OrderLog logs = objectMapper.readValue(orderLogJson, OrderLog.class);
                logs.setLogTime(logTime);
                // 将日志存入数据库
                ols.save(logs);
            } catch (Exception e) {
                // 处理反序列化和数据库存储时的异常
                System.err.println("Error processing log: " + e.getMessage());
            }
        }
        // 删除Redis中的日志项
        stringRedisTemplate.delete(orderLogRedisKey);
        // 超过所有可用站点，删除redis中订单
        stringRedisTemplate.delete(wasteOrderRedisKey);
    }

    @Override
    public FindDTO find(FindParam param) {
        int offset = (param.getPageNum() - 1) * param.getPageSize();
        String orderState = param.getOrderState();
        Integer userId = param.getUserId();
        Integer pageNum = param.getPageNum();
        Integer pageSize = param.getPageSize();
        FindDTO dto = new FindDTO();
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        if (orderState != null){
            if (orderState.equals("待接单")){
                List<OrderInfo> orderInfos = findByRedis(param);
                // 进行分页
                int totalRecords = orderInfos.size();
                int fromIndex = (pageNum - 1) * pageSize;
                int toIndex = Math.min(fromIndex + pageSize, totalRecords);
                // 检查索引范围
                if (fromIndex > totalRecords) {
                    fromIndex = totalRecords;
                    toIndex = totalRecords;
                }
                List<OrderInfo> pagedOrderInfos = orderInfos.subList(fromIndex, toIndex);
                dto.setList(pagedOrderInfos);
                dto.setTotal(totalRecords);
                return dto;
            }else if (orderState.equals("待评价")){
                queryWrapper.eq("order_state",Data.ORDER_STATE_NOT_EVALUATED);
            }else if (orderState.equals("已评价")){
                queryWrapper.eq("order_state",Data.ORDER_STATE_IN_EVALUATED);
            }else if (orderState.equals("已取消")){
                queryWrapper.eq("order_state",Data.ORDER_STATE_CANCEL);
            }else {
                queryWrapper.in("order_state",Data.ORDER_STATE_DISTRIBUTE,Data.ORDER_STATE_RECEIVED, Data.ORDER_STATE_PICKING_UP, Data.ORDER_STATE_REACHED);
            }
        }
        queryWrapper.eq("state",Data.ORDER_INFO_STATE_NORMAL).eq("user_id",userId);
        List<OrderInfo> list = oim.selectList(queryWrapper);
        ArrayList<OrderInfo> list1 = new ArrayList<>();
        List<OrderInfo> orderInfos = findByRedis(param);
        list1.addAll(list);
        list1.addAll(orderInfos);
        //分页
        int totalRecords = list1.size();
        int fromIndex = (pageNum - 1) * pageSize;
        int toIndex = Math.min(fromIndex + pageSize, totalRecords);
        // 检查索引范围
        if (fromIndex > totalRecords) {
            fromIndex = totalRecords;
            toIndex = totalRecords;
        }
        List<OrderInfo> pagedOrderInfos = list1.subList(fromIndex, toIndex);
        dto.setList(pagedOrderInfos);
        dto.setTotal(totalRecords);
        return dto;
    }

    @Override
    public AllOrderDTO findOrderByStationMasterId(AllOrderParam param, Integer offset, Integer adminId) {
        //根据当前登录站长查询对应的站点id
        Integer stationId = sc.findStationByAdminId2(adminId).getData().getStationId();
        if (stationId==null){
            return null;
        }
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        if (param.getOrderState() != null){
            queryWrapper.eq("order_state",param.getOrderState());
        }
        if (param.getStockState() != null){
            queryWrapper.eq("stock_state",param.getStockState());
        }
        if (param.getOrderNum() != null && !param.getOrderNum().equals("")){
            queryWrapper.like("order_num",param.getOrderNum());
        }
        queryWrapper.like("station_id",stationId);
        int size = Math.toIntExact(oim.selectCount(queryWrapper));
        queryWrapper.last("LIMIT " + offset + ", " + param.getPageSize());
        List<OrderInfo> infos = oim.selectList(queryWrapper);
        AllOrderDTO dto = new AllOrderDTO();
        dto.setList(infos);
        dto.setTotal(size);
        return dto;
    }

    /**
     * 查询当前用户redis中的预约订单
     * */
    public List<OrderInfo> findByRedis(FindParam param){
        Integer userId = param.getUserId();
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        String redisKeyPrefix = "waste:orderInfo:";
        Set<String> keys = stringRedisTemplate.keys(redisKeyPrefix + "*");
        List<OrderInfo> orderInfos = new ArrayList<>();
        for (String key : keys) {
            Map<Object, Object> orderData = stringRedisTemplate.opsForHash().entries(key);
            OrderInfo orderInfo = new OrderInfo();
            orderInfo.setOrderNum((String) orderData.get("order_num"));
            orderInfo.setUserId(Integer.valueOf((String) orderData.get("user_id")));
            orderInfo.setUserPhone((String) orderData.get("user_phone"));
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            orderInfo.setStartTime(LocalDateTime.parse((String) orderData.get("start_time"), formatter));
            orderInfo.setEndTime(LocalDateTime.parse((String) orderData.get("end_time"), formatter));
            orderInfo.setCreateTime(LocalDateTime.parse((String) orderData.get("create_time"), formatter));
            orderInfo.setOrderInfo((String) orderData.get("order_info"));
            orderInfo.setStationId(Integer.valueOf((String) orderData.get("station_id")));
            orderInfo.setStationName((String) orderData.get("station_name"));
            orderInfo.setStationPhone((String) orderData.get("station_phone"));
            orderInfo.setState(Integer.valueOf((String) orderData.get("state")));
            // 条件过滤
            if (orderInfo.getUserId().equals(userId)) {
                orderInfos.add(orderInfo);
            }
        }
        return orderInfos;
    }

    @Override
    public AllOrderDTO findAll(AllOrderParam param, int offset) {
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        if (param.getOrderState() != null){
            queryWrapper.eq("order_state",param.getOrderState());
        }
        if (param.getStockState() != null){
            queryWrapper.eq("stock_state",param.getStockState());
        }
        if (param.getOrderNum() != null && !param.getOrderNum().equals("")){
            queryWrapper.like("order_num",param.getOrderNum());
        }
        int size = Math.toIntExact(oim.selectCount(queryWrapper));
        queryWrapper.last("LIMIT " + offset + ", " + param.getPageSize());
        List<OrderInfo> infos = oim.selectList(queryWrapper);
        AllOrderDTO dto = new AllOrderDTO();
        dto.setList(infos);
        dto.setTotal(size);
        return dto;
    }

    @Override
    public AllOrderDTO findAllByRiderId(AllOrderParam param, Integer offset, Integer admin) {
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        if (param.getOrderState() != null){
            queryWrapper.eq("order_state",param.getOrderState());
        }
        if (param.getStockState() != null){
            queryWrapper.eq("stock_state",param.getStockState());
        }
        if (param.getOrderNum() != null && !param.getOrderNum().equals("")){
            queryWrapper.like("order_num",param.getOrderNum());
        }
        if (admin!=null){
            queryWrapper.eq("rider_id",admin);
        }
        int size = Math.toIntExact(oim.selectCount(queryWrapper));
        queryWrapper.last("LIMIT " + offset + ", " + param.getPageSize());
        List<OrderInfo> infos = oim.selectList(queryWrapper);
        AllOrderDTO dto = new AllOrderDTO();
        dto.setList(infos);
        dto.setTotal(size);
        return dto;
    }

    /**
     * 管理员分配分配骑手
     * */
    @Override
    public void acceptOrderForAdmin(String orderNum, Integer adminId) {
        //判断传入参数是否正确
        if (adminId == null) throw new OrderInfoException("用户ID不能为空", 5302);
        if (orderNum == null || orderNum.isEmpty()) throw new OrderInfoException("订单编号不能为空",5302);
        AdminInfoDTO adminInfoDTO = uc.selectAdminById(adminId).getData();
        //取出订单数据
        OrderInfo orderInfo = ois.getById(orderNum);
        if (orderInfo == null) throw new OrderInfoException("订单不存在", 5303);
        Integer orderState = orderInfo.getOrderState();
        Integer state = orderInfo.getState();
        if (orderState!=Data.ORDER_STATE_DISTRIBUTE || state!=Data.ORDER_INFO_STATE_NORMAL) throw new OrderInfoException("订单不存在", 5303);
        //将回收小哥信息加入订单
        orderInfo.setRiderId(adminId);
        orderInfo.setRiderPhone(adminInfoDTO.getAdminPhone());
        orderInfo.setOrderState(Data.ORDER_STATE_RECEIVED);
        oim.updateById(orderInfo);
    }

    /**
     * 修改预约时间
     * */
    @Override
    public void updateTime(UpdateTimeParam param) {
        Integer userId = param.getUserId();
        String orderNum = param.getOrderNum();
        LocalDateTime startTime = param.getStartTime();
        LocalDateTime endTime = param.getEndTime();
        UserInfoDTO userInfoDTO = uc.selectIntegral(userId).getData();

        //判断传入参数是否为正确
        if (userId == null) throw new OrderInfoException("用户ID不能为空", 5302);
        if (startTime == null) throw new OrderInfoException("开始时间不能为空", 5302);
        if (endTime == null) throw new OrderInfoException("结束时间不能为空", 5302);
        if (userInfoDTO==null || userInfoDTO.getUserState()!=0) throw new OrderInfoException("用户不存在",5302);

        OrderInfo orderInfo = ois.getById(orderNum);
        if (orderInfo == null || orderInfo.getState() == Data.ORDER_INFO_STATE_DELETE){
            //订单数据不存在或者还在redis中
            //将redis中订单数据取出
            String wasteOrderRedisKey = "waste:orderInfo:" + orderNum;
            Map<Object, Object> orderData = stringRedisTemplate.opsForHash().entries(wasteOrderRedisKey);
            //检查订单数据是否正确
            if (orderData == null) throw new OrderInfoException("订单不存在",5303);
            Integer orderState = Integer.valueOf((String) orderData.get("order_state"));
            Integer state = Integer.valueOf((String) orderData.get("state"));
            Integer userIdR = Integer.valueOf((String) orderData.get("userId"));
            if (!userId.equals(userIdR)) throw new OrderInfoException("订单不存在", 5303);
            if (orderState!=Data.ORDER_STATE_WAITING || state!=Data.ORDER_INFO_STATE_NORMAL) throw new OrderInfoException("订单不存在", 5303);
            //更新预约时间
            orderData.put("start_time",DateUtil.format(startTime, "yyyy-MM-dd HH:mm:ss"));
            orderData.put("end_time",DateUtil.format(endTime, "yyyy-MM-dd HH:mm:ss"));
            stringRedisTemplate.opsForHash().putAll(wasteOrderRedisKey,orderData);
        }else {
            if (Duration.between(LocalDateTime.now(),orderInfo.getStartTime()).toHours()<6){
                throw new OrderInfoException("距离订单开始时间不足六小时，无法更改预约时间订单",5305);
            }
            orderInfo.setStartTime(startTime);
            orderInfo.setEndTime(endTime);
            ois.updateById(orderInfo);
        }
    }

    /**
     * 取消订单(用户取消)
     * */
    @Override
    public void cancel(String orderNum, Integer userId, String cancelReason) {
        if (orderNum==null || userId == null || cancelReason == null || cancelReason.isEmpty()) throw new OrderInfoException("传入参数不能为空",5302);
        //将redis中订单数据取出
        String wasteOrderRedisKey = "waste:orderInfo:" + orderNum;
        Map<Object, Object> orderData = stringRedisTemplate.opsForHash().entries(wasteOrderRedisKey);
        System.out.println("redis订单数据："+orderData);
        OrderInfo info = ois.getById(orderNum);
        //检查订单数据是否正确
        if (orderData == null || orderData.isEmpty()){
            System.out.println("redis中不存在数据");
            if (info == null) throw new OrderInfoException("订单不存在",5303);
            //查询数据库
            if (info.getOrderState() == Data.ORDER_STATE_DISTRIBUTE || info.getOrderState() == Data.ORDER_STATE_RECEIVED){
                info.setOrderState(Data.ORDER_STATE_CANCEL);
                info.setCancelReason(cancelReason);
                ois.updateById(info);
                //日志
                OrderLog orderLog = new OrderLog();
                orderLog.setOrderNum(orderNum);
                orderLog.setLogTime(LocalDateTime.now());
                orderLog.setUserId(userId);
                orderLog.setUserType("用户");
                orderLog.setLogDesc("用户取消预约废品回收订单，原因：" + cancelReason);
                ols.save(orderLog);
            }else if (info.getOrderState() == Data.ORDER_STATE_PICKING_UP || info.getOrderState() == Data.ORDER_STATE_REACHED){
                info.setOrderState(Data.ORDER_STATE_CANCEL);
                info.setCancelReason(cancelReason);
                //扣减信誉分
                ScoreForm scoreForm = new ScoreForm();
                scoreForm.setScore(10);
                scoreForm.setUserId(info.getUserId());
                uc.reduceScore(scoreForm);
                ois.updateById(info);
                //日志
                OrderLog orderLog = new OrderLog();
                orderLog.setOrderNum(orderNum);
                orderLog.setLogTime(LocalDateTime.now());
                orderLog.setUserId(userId);
                orderLog.setUserType("用户");
                orderLog.setLogDesc("用户取消预约废品回收订单，原因：" + cancelReason);
                ols.save(orderLog);
            }else {
                throw new OrderInfoException("订单不存在",5303);
            }
        }else {
            System.out.println("redis中存在订单数据");
            Integer orderState = Integer.valueOf((String) orderData.get("order_state"));
            Integer state = Integer.valueOf((String) orderData.get("state"));
            Integer userIdR = Integer.valueOf((String) orderData.get("userId"));
            if (!userId.equals(userIdR)) throw new OrderInfoException("订单不存在", 5303);
            if (state!=Data.ORDER_INFO_STATE_NORMAL) throw new OrderInfoException("订单不存在", 5303);
            //新增日志记录(在redis中)
            OrderLog orderLog = new OrderLog();
            orderLog.setOrderNum(orderNum);
            orderLog.setLogTime(LocalDateTime.now());
            orderLog.setUserId(userId);
            orderLog.setUserType("用户");
            orderLog.setLogDesc("用户取消预约废品回收订单，原因：" + cancelReason);
            //更新数据
            orderData.put("order_state",String.valueOf(Data.ORDER_STATE_CANCEL));
            orderData.put("cancel_reason",cancelReason);
            stringRedisTemplate.opsForHash().putAll(wasteOrderRedisKey,orderData);
            String orderLogRedisKey = "waste:orderLog:" + orderNum;
            stringRedisTemplate.opsForList().rightPush(orderLogRedisKey, JSONUtil.toJsonStr(orderLog));
            //数据写入数据库（将订单和全部日志一起写回mysql数据库）
            OrderInfo orderInfo = objectMapper.convertValue(orderData, OrderInfo.class);
            ois.save(orderInfo);
            //将日志写回数据库
            String orderLogJson;
            while ((orderLogJson = stringRedisTemplate.opsForList().leftPop(orderLogRedisKey)) != null) {
                try {
                    // 反序列化日志
                    OrderLogDTO log = objectMapper.readValue(orderLogJson, OrderLogDTO.class);
                    String logTimeString = log.getLogTime();
                    LocalDateTime logTime = LocalDateTime.parse(logTimeString, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
                    OrderLog logs = objectMapper.readValue(orderLogJson, OrderLog.class);
                    logs.setLogTime(logTime);
                    // 将日志存入数据库
                    ols.save(logs);
                } catch (Exception e) {
                    // 处理反序列化和数据库存储时的异常
                    System.err.println("Error processing log: " + e.getMessage());
                }
            }
            // 删除Redis中的日志项
            stringRedisTemplate.delete(orderLogRedisKey);
            // 超过所有可用站点，删除redis中订单
            stringRedisTemplate.delete(wasteOrderRedisKey);
        }
    }

    /**
     * 取消订单(骑手取消)
     * */
    @Override
    public void cancelByRider(String orderNum, Integer adminId, String cancelReason) {
        //判断传入参数是否正确
        if (orderNum==null || adminId == null || cancelReason == null || cancelReason.isEmpty()) throw new OrderInfoException("传入参数不能为空",5302);
        OrderInfo orderInfo = ois.getById(orderNum);
        if (orderInfo == null || orderInfo.getOrderState() != Data.ORDER_STATE_REACHED) throw new OrderInfoException("订单不存在", 5303);
        AdminInfoDTO adminInfoDTO = uc.selectAdminById(adminId).getData();
        if (adminInfoDTO == null || adminInfoDTO.getAdminState() != 0) throw new OrderInfoException("骑手不存在",5302);
        //取消订单
        orderInfo.setOrderState(Data.ORDER_STATE_CANCEL);
        orderInfo.setCancelReason(cancelReason);
        ois.updateById(orderInfo);
        //新增日志
        OrderLog orderLog = new OrderLog();
        orderLog.setLogTime(LocalDateTime.now());
        orderLog.setUserId(adminId);
        orderLog.setUserType("骑手");
        orderLog.setOrderNum(orderNum);
        orderLog.setLogDesc("骑手取消订单");
        ols.save(orderLog);
    }

    /**
     * 确认并支付（待定）
     * */
    @Override
    public String confirm(OkOderInfoParam param) throws IOException, AlipayApiException {
        //判断传入参数是否正确
        String  orderNum = param.getOrderNum();
        BigDecimal money = param.getMoney();
        List<OkOderInfoForm.WasteInfo> wasteList = param.getWasteList();
        if (orderNum == null || money == null || wasteList.size() == 0) throw new OrderInfoException("传入参数不能为空",5302);
        OrderInfo orderInfo = ois.getById(orderNum);
        System.out.println(orderInfo);
        System.out.println(orderInfo.getOrderState());
        if (orderInfo == null || orderInfo.getOrderState() != Data.ORDER_STATE_REACHED) throw new OrderInfoException("订单不存在", 5301);

        //判断废品状态是否正常
        List<OkOderInfoForm.WasteInfo> wasteInfos = param.getWasteList();
        //计算总重量，一千克一积分
        double totalWeight = 0;
        for (OkOderInfoForm.WasteInfo wasteInfo : wasteInfos) {
            WasteTypeDTO wasteTypeDTO = sc.findByTypeId(wasteInfo.getTypeId()).getData();
            if (wasteTypeDTO == null || wasteTypeDTO.getTypeState() != 0) throw new OrderInfoException("废品类型不存在",5302);
            totalWeight += wasteInfo.getWeight();
        }
        // 每千克一积分
        int totalPoints = (int) totalWeight;
        //更新用户积分
        IntegralForm form = new IntegralForm();
        form.setUserId(orderInfo.getUserId());
        form.setIntegral(totalPoints);
        uc.addIntegralById(form);

        OrderWasteInfoDTO wasteInfoDTO = new OrderWasteInfoDTO();
        wasteInfoDTO.setWasteList(wasteList);
        //更新订单
        orderInfo.setMoney(money);
        orderInfo.setOrderEndTime(LocalDateTime.now());
        orderInfo.setROrderInfo(JSONUtil.toJsonStr(wasteInfoDTO));
        orderInfo.setOrderState(Data.ORDER_STATE_NOT_EVALUATED);
        orderInfo.setStockState(Data.STOCK_STATE_NOT_IN_STOCK);
        ois.updateById(orderInfo);
        //支付
        // 生成过期时间字符串
        long expireTimeInMillis = System.currentTimeMillis() + 15 * 60 * 1000;
        String expireString = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(expireTimeInMillis));
        //  实例化网页支付请求对象
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        // 使用 JSON 工具构建请求参数
        HashMap<String, Object> params = new HashMap<>();
        params.put("out_trade_no", orderNum);
        params.put("total_amount", money.setScale(2, RoundingMode.HALF_UP).doubleValue());
        params.put("subject", "再生道");
        params.put("body", "订单支付");
        params.put("product_code", "FAST_INSTANT_TRADE_PAY");
        params.put("time_expire", expireString);
        // 将参数转换为 JSON 字符串
        String content = JSONUtil.toJsonStr(params);
        request.setBizContent(content);
        // 设置同步和异步回调地址
        request.setReturnUrl("http://localhost:8080/#/ridermain/riderorder");
        request.setNotifyUrl("");
        // 执行网页支付请求
        AlipayTradePagePayResponse response = alipayClient.sdkExecute(request);
        // 判断支付宝响应结果
        if (response.isSuccess()) {
            //按照支付宝接口的标准手动拼接请求 URL
            String body = "https://openapi-sandbox.dl.alipaydev.com/gateway.do"+"?"+response.getBody();
            // 将订单编号发送到自检队列
            rabbitTemplate.convertAndSend("order_check_queue", orderNum);
            return body;
        } else {
            // 打印错误信息
            System.out.println("支付宝响应失败信息: " + response.getMsg() + " - " + response.getSubMsg());
            throw new OrderInfoException("发起支付失败",5304);
        }
    }

    @Override
    public Page<OrderInfo> findAppointment(FindAppointmentParam param) {
        Page<OrderInfo> page = new Page<>(param.getPageNum(), param.getPageSize());
        Integer stationId = param.getStationId();
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        if (stationId != null) {
            queryWrapper.eq("station_id",stationId).eq("state",Data.ORDER_INFO_STATE_NORMAL);
        }else {
            queryWrapper.eq("state",Data.ORDER_INFO_STATE_NORMAL);
        }
        return oim.selectPage(page,queryWrapper);
    }

    @Override
    public Double queryWeight(String orderNum, Integer typeId) {
        //判断传入参数是否正确
        if(orderNum == null || typeId == null) throw new OrderInfoException("传入参数不正确",5302);
        OrderInfo orderInfo = ois.getById(orderNum);
        if (orderInfo.getState() == Data.ORDER_INFO_STATE_DELETE || orderInfo.getStockState() != Data.STOCK_STATE_NOT_IN_STOCK) throw new OrderInfoException("订单不存在", 5301);
        WasteTypeDTO wasteTypeDTO = sc.findByTypeId(typeId).getData();
        if (wasteTypeDTO == null || wasteTypeDTO.getTypeState() != 0) throw new OrderInfoException("废品类型不存在",5302);
        //反序列化骑手订单信息
        OrderWasteInfoDTO wasteInfoDTO = JSONUtil.toBean(orderInfo.getROrderInfo(), OrderWasteInfoDTO.class);
        List<OkOderInfoForm.WasteInfo> wasteList = wasteInfoDTO.getWasteList();
        for (OkOderInfoForm.WasteInfo wasteInfo : wasteList) {
            if (wasteInfo.getTypeId() == typeId){
                return wasteInfo.getWeight();
            }
        }
        return null;
    }

    private double calculateDistance(BigDecimal userLatitude, BigDecimal userLongitude,
                                     BigDecimal stationLatitude, BigDecimal stationLongitude) {
        final int R = 6371; // 地球半径，单位为公里
        double latDistance = Math.toRadians(stationLatitude.doubleValue() - userLatitude.doubleValue());
        double lonDistance = Math.toRadians(stationLongitude.doubleValue() - userLongitude.doubleValue());

        double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2) +
                Math.cos(Math.toRadians(userLatitude.doubleValue())) * Math.cos(Math.toRadians(stationLatitude.doubleValue())) *
                        Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        return R * c; // 返回的距离，单位为公里
    }

    /**
     * 自检
     * */
    @Override
    public boolean orderCheck(String orderNum) {
        System.out.println("检查订单支付状态");
        //查询支付宝的支付状态(到底有没有转账)
        //设置请求参数
        AlipayTradeQueryRequest alipayRequest = new AlipayTradeQueryRequest();
        alipayRequest.setBizContent("{\"out_trade_no\":\""+ orderNum+"\"}");
        //请求
        try {
            String result = alipayClient.execute(alipayRequest).getBody();//响应的结果是个JSON格式
            //输出
            String orderInfo= JSONUtil.parseObj(result).get("alipay_trade_query_response").toString();
            String payCode=JSONUtil.parseObj(orderInfo).get("code").toString();
            System.out.println(result);
            //10000表示查询成功
            if("10000".equals(payCode)) {//表示发起支付
                String payState = JSONUtil.parseObj(orderInfo).get("trade_status").toString();//支付状态
                if ("TRADE_SUCCESS".equals(payState)){
                    //支付成功
                    String payDate =JSONUtil.parseObj(orderInfo).get("send_pay_date").toString();//支付时间(只有支付成功之后才能取到支付时间)
                    //将支付时间填入订单中
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 根据实际格式调整
                    Date date = sdf.parse(payDate);
                    // 转换为本地时间
                    LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                    OrderInfo info = ois.getById(orderNum);
                    info.setPaymentTime(localDateTime);
                    ois.updateById(info);
                    return false;
                }
                else {//发起支付但没有完成付款
                    return true;
                }
            }else {//没有发起支付
                return true;
            }
        }catch (AlipayApiException e){
            e.printStackTrace();
            throw new OrderInfoException("支付异常",5307);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 手动补偿
     * */
    @Override
    public void updateOrder(String orderNum) {
        //将数据回滚
        OrderInfo orderInfo = ois.getById(orderNum);
        orderInfo.setOrderState(Data.ORDER_STATE_REACHED);
        orderInfo.setOrderEndTime(null);
        orderInfo.setROrderInfo(null);
        orderInfo.setMoney(null);
        orderInfo.setStockState(null);
        ois.updateById(orderInfo);
        //新增日志到数据库
        OrderLog orderLog = new OrderLog();
        orderLog.setOrderNum(orderNum);
        orderLog.setLogTime(LocalDateTime.now());
        orderLog.setLogDesc("转账失败，请重新提交订单");
        orderLog.setUserId(orderInfo.getRiderId());
        orderLog.setUserType("骑手");
        ols.save(orderLog);
    }
}
